package presentation;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

import control.CControl;

public class PCarPanel extends JPanel {
	private static final long serialVersionUID = 1L;
	private Font largeFont, tinyFont, smallFont;
	private Image carImage = null, accImage = null;
	private final Double IMAGE_WIDTH = 858., IMAGE_HEIGHT= 470.,
	WHEEL_WIDTH = 158., WHEEL_HEIGHT=56., RL_Y = 20., RR_Y = 393., FL_Y=12.,
	FR_Y = 401., F_X = 487., R_X = 8.;
	private PWheelTempMarker[] wheelTempMarkers = new PWheelTempMarker[4];
	private HashMap<String,PValue> textValues = new LinkedHashMap<String,PValue>();
	private PTextValue rlTrip, rrTrip, flTrip, frTrip;
	private PNumberValue fAccX, fAccY, fAccZ, rAccX, rAccY, rAccZ;
	private final int MIN_ACC_DOT_DIAMETER = 4;
	private final double MAX_ACC = 2000.;
	
	public PCarPanel(CControl cControl) {
		//textValues.put("Oil on/off switch value:", new PTextValue(cControl,"OilOnOff"));
		//textValues.put("Air to fuel ratio:", new PTextValue(cControl,"LambdaValueECU"));
		//textValues.put("Gear-clutch drive mode:", new PPatternValue(cControl,"DRVModeGC"));
		//textValues.put("ECU drive mode:", new PPatternValue(cControl,"DRVModeECU"));
		textValues.put("Trip distance:", new PTextValue(cControl,"FSN_TripDistance"));
		textValues.put("Trip distance 1:", new PTextValue(cControl,"FSN_TripDistance"));
		textValues.put("Trip distance 2:", new PTextValue(cControl,"FSN_TripDistance"));
		textValues.put("Trip distance 3:", new PTextValue(cControl,"FSN_TripDistance"));
		largeFont = new Font("Arial", Font.PLAIN, 16);
		smallFont = new Font("Arial", Font.PLAIN, 12);
		tinyFont = new Font("Arial", Font.PLAIN, 10);
		
		rlTrip = new PTextValue(cControl,"RSN_TripLeft");
		rrTrip = new PTextValue(cControl,"RSN_TripRight");
		flTrip = new PTextValue(cControl,"FSN_TripLeft");
		frTrip = new PTextValue(cControl,"FSN_TripRight");
		
		fAccX = new PNumberValue(cControl,"FSN_GyroAccX");
		fAccY = new PNumberValue(cControl,"FSN_GyroAccY");
		fAccZ = new PNumberValue(cControl,"FSN_GyroAccZ");
		rAccX = new PNumberValue(cControl,"RSN_GyroAccX");
		rAccY = new PNumberValue(cControl,"RSN_GyroAccY");
		rAccZ = new PNumberValue(cControl,"RSN_GyroAccZ");
		
		int wheelTempLow = 50, wheelTempMedium = 70, wheelTempHigh = 90;
		try {
			wheelTempLow = Integer.parseInt(cControl.getSettingsParameter("wheeltempmedium"));
			wheelTempMedium = Integer.parseInt(cControl.getSettingsParameter("wheeltemphigh"));
			wheelTempHigh = Integer.parseInt(cControl.getSettingsParameter("wheeltempveryhigh"));
		}catch (Exception e) {}
		
		try {
			carImage = ImageIO.read(new File(cControl.getRootPath() + "img/car.png"));
			accImage = ImageIO.read(new File(cControl.getRootPath() + "img/acc.png"));
		} catch (IOException e) {
			cControl.addError("Unable to access images for GUI: " + e.getMessage());
		}
		wheelTempMarkers[0] = new PWheelTempMarker(IMAGE_WIDTH,R_X,
				RL_Y,WHEEL_WIDTH,WHEEL_HEIGHT,wheelTempLow, wheelTempMedium, wheelTempHigh);
		wheelTempMarkers[1] = new PWheelTempMarker(IMAGE_WIDTH,F_X,
				FL_Y,WHEEL_WIDTH,WHEEL_HEIGHT,wheelTempLow, wheelTempMedium, wheelTempHigh);
		wheelTempMarkers[2] = new PWheelTempMarker(IMAGE_WIDTH,R_X,
				RR_Y,WHEEL_WIDTH,WHEEL_HEIGHT,wheelTempLow, wheelTempMedium, wheelTempHigh);
		wheelTempMarkers[3] = new PWheelTempMarker(IMAGE_WIDTH,F_X,
				FR_Y,WHEEL_WIDTH,WHEEL_HEIGHT,wheelTempLow, wheelTempMedium, wheelTempHigh);
		
		cControl.addRegisterObserver("RSN_TireTempFLL", wheelTempMarkers[0]);
		cControl.addRegisterObserver("RSN_TireTempFLM", wheelTempMarkers[0]);
		cControl.addRegisterObserver("RSN_TireTempFLR", wheelTempMarkers[0]);
		cControl.addRegisterObserver("FSN_TireTempFLL", wheelTempMarkers[1]);
		cControl.addRegisterObserver("FSN_TireTempFLM", wheelTempMarkers[1]);
		cControl.addRegisterObserver("FSN_TireTempFLR", wheelTempMarkers[1]);
		cControl.addRegisterObserver("RSN_TireTempFRL", wheelTempMarkers[2]);
		cControl.addRegisterObserver("RSN_TireTempFRM", wheelTempMarkers[2]);
		cControl.addRegisterObserver("RSN_TireTempFRR", wheelTempMarkers[2]);
		cControl.addRegisterObserver("FSN_TireTempFRL", wheelTempMarkers[3]);
		cControl.addRegisterObserver("FSN_TireTempFRM", wheelTempMarkers[3]);
		cControl.addRegisterObserver("FSN_TireTempFRR", wheelTempMarkers[3]);
	}

	protected void paintComponent(Graphics g) {
    	super.paintComponent(g);
    	Graphics2D g2 = (Graphics2D)g;
    	g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
    			RenderingHints.VALUE_ANTIALIAS_ON);
    	
    	g2.setStroke(new BasicStroke(1));
    	
    	g2.setFont(largeFont);
    	
    	Double lines = Math.ceil(textValues.size()/2.);
    	FontRenderContext frc = g2.getFontRenderContext();
    	Double textHeightD = largeFont.getStringBounds("Hg", frc).getHeight();
    	int textHeight = textHeightD.intValue();
    	int textSpacing = 5;
    	Double textOffsetD = getHeight()/3.- (lines.intValue()*textHeight + 
    			(lines.intValue()-1)*textSpacing);
    	int textOffset = textOffsetD.intValue();
    	int center = getWidth()/2;
    	
    	// TEXT:
    	Iterator<String> texts = textValues.keySet().iterator();
    	int number = 0;
    	String text, value;
    	Double valueWidth; 
    	while(texts.hasNext()) {
    		text = texts.next();
    		value = textValues.get(text).value;
    		valueWidth = largeFont.getStringBounds(value, frc).getWidth();
    		if (number%2 == 0) {
        		g2.drawString(text, center-430, textOffset+number/2*(textHeight+textSpacing));
        		g2.drawString(value, center-30-valueWidth.intValue(), textOffset+number/2*(textHeight+textSpacing));
    		} else {
        		g2.drawString(text, center+30, textOffset+number/2*(textHeight+textSpacing));
        		g2.drawString(value, center+430-valueWidth.intValue(), textOffset+number/2*(textHeight+textSpacing));
    		}
    		
    		number++;
    	}
    	// --------------------------------------------------------
    	
    	// CAR IMAGE:
    	Double carPartHeightD = 2.*getHeight()/3.;
    	int carPartHeight = carPartHeightD.intValue();
    	Double carPartOffsetD = getHeight()/3.;
    	int carPartOffset = carPartOffsetD.intValue();
    	
    	int imageHeight = carPartHeight-carPartHeight/4;
    	Double imageWidthD = imageHeight*(IMAGE_WIDTH/IMAGE_HEIGHT);
    	int imageWidth = imageWidthD.intValue();
    	int imageX = (getWidth()-imageWidth)/2;
    	int imageY = (carPartHeight-imageHeight)/2+carPartOffset;
    	
    	g2.drawImage(carImage.getScaledInstance(imageWidth, 
    			imageHeight, Image.SCALE_SMOOTH), imageX, 
    			imageY, null);
    	// ---------------------------------------------------------
    	
    	// WHEEL TRIP DISTANCES:
    	g2.setFont(smallFont);
    	g2.setPaint(Color.black);
    	g2.drawString("Trip: " + rlTrip.value, 
    			imageX+wheelTempMarkers[0].getScaledX()+
    			wheelTempMarkers[0].getScaledWidth()+5, 
    			imageY+wheelTempMarkers[0].getScaledY(wheelTempMarkers[0].LEFT) +
    			wheelTempMarkers[0].getScaledHeight()+8);
    	
    	g2.drawString("Trip: " + flTrip.value, 
    			imageX+wheelTempMarkers[1].getScaledX()+
    			wheelTempMarkers[1].getScaledWidth()+5, 
    			imageY+wheelTempMarkers[1].getScaledY(wheelTempMarkers[0].LEFT) +
    			wheelTempMarkers[1].getScaledHeight()+8);
    	
    	g2.drawString("Trip: " + rrTrip.value, 
    			imageX+wheelTempMarkers[2].getScaledX()+
    			wheelTempMarkers[2].getScaledWidth()+5, 
    			imageY+wheelTempMarkers[2].getScaledY(wheelTempMarkers[0].LEFT) +
    			wheelTempMarkers[2].getScaledHeight()+8);
    	
    	g2.drawString("Trip: " + frTrip.value, 
    			imageX+wheelTempMarkers[3].getScaledX()+
    			wheelTempMarkers[3].getScaledWidth()+5, 
    			imageY+wheelTempMarkers[3].getScaledY(wheelTempMarkers[0].LEFT) +
    			wheelTempMarkers[3].getScaledHeight()+8);
    	// ---------------------------------------------------------
    	
    	// WHEEL TEMPERATURES:
    	for (int i = 0; i < wheelTempMarkers.length; i++) {
    		wheelTempMarkers[i].setImageWidth(imageWidthD);
        	g2.setPaint(wheelTempMarkers[i].getLeftTempColor());
        	g2.fillRect(imageX+wheelTempMarkers[i].getScaledX(), 
        			imageY+wheelTempMarkers[i].getScaledY(wheelTempMarkers[i].LEFT),
        			wheelTempMarkers[i].getScaledWidth(),
        			wheelTempMarkers[i].getScaledHeight());
        	
        	wheelTempMarkers[i].setImageWidth(imageWidthD);
        	g2.setPaint(wheelTempMarkers[i].getCenterTempColor());
        	g2.fillRect(imageX+wheelTempMarkers[i].getScaledX(), 
        			imageY+wheelTempMarkers[i].getScaledY(wheelTempMarkers[i].CENTER),
        			wheelTempMarkers[i].getScaledWidth(),
        			wheelTempMarkers[i].getScaledHeight());
        	
        	wheelTempMarkers[i].setImageWidth(imageWidthD);
        	g2.setPaint(wheelTempMarkers[i].getRightTempColor());
        	g2.fillRect(imageX+wheelTempMarkers[i].getScaledX(), 
        			imageY+wheelTempMarkers[i].getScaledY(wheelTempMarkers[i].RIGHT),
        			wheelTempMarkers[i].getScaledWidth(),
        			wheelTempMarkers[i].getScaledHeight());
    	}
    	
    	//----------------------------------------------------------------
    	
    	// ACCELARATION DIALS:
    	int accDiameter = carPartHeight/3;
    	int accY = imageHeight/2-accDiameter/2+imageY;
    	int acc1X = imageX/2-accDiameter/2;
    	int acc2X = getWidth()-(imageX/2+accDiameter/2);
    	
    	// ACCELERATION IMAGE:
    	g2.drawImage(accImage.getScaledInstance(accDiameter, 
    			accDiameter, Image.SCALE_SMOOTH), acc1X, 
    			accY, null);
    	g2.drawImage(accImage.getScaledInstance(accDiameter, 
    			accDiameter, Image.SCALE_SMOOTH), acc2X, 
    			accY, null);
    	
    	// ACCELERATION LABELS:
    	g2.setFont(largeFont);
    	g2.setPaint(Color.black);
    	String accLabel = "Acceleration:";
    	Double textWidthD = largeFont.getStringBounds(accLabel, frc).getWidth();
    	int textWidth = textWidthD.intValue();
    	g2.drawString(accLabel, acc1X+accDiameter/2-textWidth/2, accY-10);
    	g2.drawString(accLabel, acc2X+accDiameter/2-textWidth/2, accY-10);
    	
    	g2.setFont(tinyFont);
    	
    	for (int i = -2; i < 3; i++) {
    		String GLabel = i+"G";
    		textWidthD = largeFont.getStringBounds(GLabel, frc).getWidth();
        	textWidth = textWidthD.intValue();
        	Double offset = accDiameter/4.*i;
        	g2.drawString(GLabel, acc1X-textWidth-5, accY+accDiameter/2+offset.intValue()+3);
        	g2.drawString(GLabel, acc2X-textWidth-5, accY+accDiameter/2+offset.intValue()+3);
        	g2.drawString(GLabel, acc1X-textWidth/2+accDiameter/2+offset.intValue(),accY+accDiameter+12);
        	g2.drawString(GLabel, acc2X-textWidth/2+accDiameter/2+offset.intValue(),accY+accDiameter+12);
    	}
    	// -----------------------------------------------------------------
    	
    	// ACCELERATION DOTS:
    	g2.setPaint(Color.red);
    	Double dot1Diameter = Math.abs(rAccZ.value/MAX_ACC*accDiameter/2);
    	dot1Diameter = (dot1Diameter.intValue() < MIN_ACC_DOT_DIAMETER) ? MIN_ACC_DOT_DIAMETER : dot1Diameter;
    	Double dot1X = acc1X + rAccX.value/MAX_ACC*accDiameter/2 + accDiameter/2;
    	Double dot1Y = accY + rAccY.value/MAX_ACC*accDiameter/2 + accDiameter/2;
    	g2.fillOval(dot1X.intValue()-dot1Diameter.intValue()/2, dot1Y.intValue()-dot1Diameter.intValue()/2, dot1Diameter.intValue(), dot1Diameter.intValue());
    	
    	Double dot2Diameter = Math.abs(fAccZ.value/MAX_ACC*accDiameter/2);
    	dot2Diameter = (dot2Diameter.intValue() < MIN_ACC_DOT_DIAMETER) ? MIN_ACC_DOT_DIAMETER : dot2Diameter;
    	Double dot2X = acc2X + fAccX.value/MAX_ACC*accDiameter/2 + accDiameter/2;
    	Double dot2Y = accY + fAccY.value/MAX_ACC*accDiameter/2 + accDiameter/2;
    	g2.fillOval(dot2X.intValue()-dot2Diameter.intValue()/2, dot2Y.intValue()-dot2Diameter.intValue()/2, dot2Diameter.intValue(), dot2Diameter.intValue());
    	//-----------------------------------------------------------------
	}
}
